// Implementation of an icon for FLTK toolkit
// Copyright 2005 (C) Ralph Thomas

#include <toolkit/fltk/fltkIcon.h>
#include <toolkit/fltk/aspectImage.h>
#include <fltk/SharedImage.h>
#include <util/resources.h>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <map>

namespace bfs = boost::filesystem;

namespace toolkit {
	//
	/// This is the internal implementation class for the fltkIcon.
	//
	class fltkIconImpl : public fltkIcon {
		typedef std::map<iconSize, fltk::SharedImage*> iconMap;
		//
		/// Store pointers of all icons we have returned so that we may
		/// destroy them when we are destroyed.
		//
		iconMap _icons;
		//
		/// The MIME type whose icon we should look for.
		//
		std::string _type;
	  public:
		//
		// fltkIconImpl( const std::string type )
		//
		/// Create a new fltkIconImpl for the given type.
		///
		/// \param	type	the type to create an icon for.
		//
		fltkIconImpl( const std::string& type ) : _type( type ) {}
		//
		// ~fltkIconImpl()
		//
		/// Release any allocated images.
		//
		virtual ~fltkIconImpl() {
			iconMap::iterator i;
			//
			// Iterate through all of the images and release them.
			//
			for( i = _icons.begin(); i != _icons.end(); i++ ) {
				i->second->clear_cache();
				i->second->destroy();
				i->second->remove();
			}
		}
		const fltk::Image* get( iconSize size ) const {
			//
			// See if we already created this icon.
			//
			iconMap::const_iterator i( _icons.find( size ) );
			if( i != _icons.end() ) return i->second;
			//
			// Find the filename for the icon we need to load.
			//
			std::string filename;
			switch( size ) {
			  case k16x16:
				filename = "16.png";
				break;
			  case k22x22:
				filename = "22.png";
				break;
			  case k32x32:
				filename = "32.png";
				break;
			  case k48x48:
				filename = "48.png";
				break;
			  case k64x64:
				filename = "64.png";
				break;
			  case k128x128:
				filename = "128.png";
				break;
			  default:
				//
				// Unknown icon size.
				//
				return 0;
			}
			bfs::path res = util::getResource( _type, filename );
			if( res.empty() ) return 0;
			//
			// Load the icon.
			//
			fltk::SharedImage* im(
				fltk::pngImage::get( res.string().c_str() ) );
			if( !im ) return 0;
			//
			// Cache the icon. This is a const call (because
			// this method is a "get", and callers shouldn't have
			// to care if the icon was cached or not).
			//
			const_cast<fltkIconImpl*>( this )->_icons[size] = im;
			//
			// Return the icon to the caller.
			//
			return im;
		}
	};
	//
	/// Preview icon implementation.
	//
	class fltkPreviewImpl : public fltkIcon {
		fltk::SharedImage* _preview;
		fltk::AspectImage _proxy;
	  public:
		fltkPreviewImpl( fltk::SharedImage* preview )
		: _preview( preview ) {
			_proxy.setSource( preview );
		}
		virtual ~fltkPreviewImpl() {
			if( _preview ) _preview->remove();
		}
		const fltk::Image* get( iconSize s ) const {
			return &_proxy;
		}
	};
	//
	// Virtual destructor implementations.
	//
	fltkIcon::~fltkIcon() {}
	icon::~icon() {}
	//
	// Getter method.
	//
	icon* icon::create( const bfs::path& file, const std::string& type ) {
		return new fltkIconImpl( type );
	}
	icon* icon::preview( const bfs::path& file ) {
		fltk::SharedImage* im( fltk::pngImage::get( file.string().c_str() ) );
		if( !im ) return 0;
		return new fltkPreviewImpl( im );
	}
};

